package cn.sc.summer.construction.role;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.CharSequenceUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import cn.sc.summer.constant.model.PageResult;
import cn.sc.summer.constant.util.AssertUtil;
import cn.sc.summer.daoapi.dao.SysRoleMapper;
import cn.sc.summer.daoapi.dao.SysRoleUserMapper;
import cn.sc.summer.daoapi.dao.SysRouteRoleMapper;
import cn.sc.summer.daoapi.po.SysRole;
import cn.sc.summer.daoapi.po.SysRoleUser;
import cn.sc.summer.daoapi.po.SysRouteRole;
import cn.sc.summer.domain.role.SysRoleService;
import cn.sc.summer.domain.route.SysRouteService;
import cn.sc.summer.exception.enums.CommonExceptionEnum;
import cn.sc.summer.exception.exceptions.CommonException;
import cn.sc.summer.protocol.form.role.RoleBindForm;
import cn.sc.summer.protocol.form.role.RoleForm;
import cn.sc.summer.protocol.form.role.RoleGetForm;
import cn.sc.summer.protocol.params.SysApiInfo;
import cn.sc.summer.protocol.vo.role.RoleInfoVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 类名：角色信息建设层
 *
 * @author a-xin
 * @date 2024/8/14 16:56
 */
@Slf4j
@Service
public class SysRoleServiceImpl implements SysRoleService {

    @Resource
    private SysRoleMapper sysRoleMapper;

    @Resource
    private SysRoleUserMapper sysRoleUserMapper;

    @Resource
    private SysRouteService sysRouteService;

    @Resource
    private SysRouteRoleMapper sysRouteRoleMapper;

    /**
     * 新增角色信息
     *
     * @param form 角色信息
     * @return 角色ID
     */
    @Override
    public String addRole(RoleForm form) {
        sysRoleMapper.exceptionIfExit(new LambdaQueryWrapper<SysRole>()
                .eq(SysRole::getName, form.getName()), "已存在对应的角色名称!");
        SysRole sysRole = new SysRole();
        sysRole.setName(form.getName());
        sysRoleMapper.insert(sysRole);
        return sysRole.getId();
    }

    /**
     * 更新角色信息
     *
     * @param form 角色信息
     * @return 角色ID
     */
    @Override
    public Boolean updateRole(RoleForm form) {
        Optional.ofNullable(sysRoleMapper.selectById(form.getId()))
                .ifPresent(sysRole -> {
                    sysRoleMapper.exceptionIfExit(new LambdaQueryWrapper<SysRole>()
                            .ne(SysRole::getId, form.getId())
                            .eq(SysRole::getName, form.getName()), "已存在对应的角色名称!");
                    sysRole.setName(form.getName());
                    sysRoleMapper.updateById(sysRole);
                });
        return Boolean.TRUE;
    }

    /**
     * 删除角色信息
     *
     * @param roleId 角色ID
     * @return 是否成功
     */
    @Override
    public Boolean delRole(String roleId) {
        sysRoleUserMapper.exceptionIfExit(new LambdaQueryWrapper<SysRoleUser>()
                .eq(SysRoleUser::getRoleId, roleId), "该角色已绑定相关人员，不能删除!");
        return sysRoleMapper.deleteById(roleId) > 0;
    }

    /**
     * 获取所有角色信息
     *
     * @param form 搜索表单
     * @return 角色信息
     */
    @Override
    public PageResult<RoleInfoVO> getAllRole(RoleGetForm form) {
        return sysRoleMapper.selectPage(form, new LambdaQueryWrapper<SysRole>()
                .like(CharSequenceUtil.isNotBlank(form.getSearch()), SysRole::getName, form.getSearch()), RoleInfoVO.class);
    }

    /**
     * 角色绑定路由信息
     *
     * @param form 角色和路由信息
     * @return 是否成功
     */
    @Override
    public Boolean roleBindRoute(RoleBindForm form) {
        Optional.ofNullable(sysRoleMapper.selectById(form.getRoleId()))
                .orElseThrow(() -> new CommonException("不存在对应的角色信息!"));
        List<String> routeIds = form.getRouteIds();
        AssertUtil.functionIfPre(routeIds, CollUtil::isNotEmpty, () -> {
            sysRouteService.checkRouteById(routeIds);
            String roleId = form.getRoleId();
            List<String> bindRouteIdList = sysRouteRoleMapper.selectList(new LambdaQueryWrapper<SysRouteRole>()
                            .select(SysRouteRole::getRouteId)
                            .eq(SysRouteRole::getRoleId, roleId))
                    .stream().map(SysRouteRole::getRouteId).collect(Collectors.toList());

            List<String> needDel = bindRouteIdList.stream()
                    .filter(item -> !routeIds.contains(item)).collect(Collectors.toList());
            List<String> needBind = routeIds.stream()
                    .filter(item -> !bindRouteIdList.contains(item)).collect(Collectors.toList());

            AssertUtil.functionIfPre(needBind, CollUtil::isNotEmpty, () -> {
                List<SysRouteRole> sysRouteRoles = needBind.stream().map(routeId -> {
                    SysRouteRole sysRouteRole = new SysRouteRole();
                    sysRouteRole.setRoleId(roleId);
                    sysRouteRole.setRouteId(routeId);
                    return sysRouteRole;
                }).collect(Collectors.toList());
                sysRouteRoleMapper.insertBatch(sysRouteRoles);
            });

            AssertUtil.functionIfPre(needDel, CollUtil::isNotEmpty, () -> {
                sysRouteRoleMapper.delete(new LambdaQueryWrapper<SysRouteRole>()
                        .eq(SysRouteRole::getRoleId, roleId)
                        .in(SysRouteRole::getRouteId, needDel));
            });

        });
        return Boolean.TRUE;
    }

    /**
     * 校验角色信息是否正确
     *
     * @param roleIds 角色ID
     */
    @Override
    public void checkRole(List<String> roleIds) {
        AssertUtil.functionIfPre(roleIds, CollUtil::isNotEmpty, () -> {
            int size = sysRoleMapper.selectBatchIds(roleIds).size();
            CommonExceptionEnum.NORMAL_EXCEPTION.exceptionIf(roleIds.size() != size, "不存在对应的角色信息");
        });
    }

    /**
     * 获取角色对应绑定所有apiID
     *
     * @param roleIds 角色ID
     * @return api信息
     */
    @Override
    public List<SysApiInfo> getApiInfoByRoleIds(List<String> roleIds) {
        List<SysRouteRole> sysRouteRoles = sysRouteRoleMapper.selectList(new LambdaQueryWrapper<SysRouteRole>()
                .in(SysRouteRole::getRoleId, roleIds));
        return AssertUtil.functionIfPre(sysRouteRoles, CollUtil::isNotEmpty, () -> {
            List<String> allRouteIds = sysRouteRoles.stream().map(SysRouteRole::getRouteId)
                    .collect(Collectors.toList());
            return sysRouteService.getRouteApiInfo(allRouteIds);
        }, new ArrayList<>());
    }
}
